import { HttpInterceptorFn, HttpErrorResponse, HttpEvent } from '@angular/common/http';
import { inject } from '@angular/core';
import { Observable, throwError, of } from 'rxjs';
import { catchError, finalize, mergeMap, switchMap, delay } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { actionLoadStart, actionLoadFinish } from './load.actions';
import { getInterceptorConfig, InterceptorConfig } from './interceptor.models';
import { Constants } from '@shared/models/constants';
import { AuthService } from '@core/auth/auth.service';

// 全局请求计数器（用于并发请求管理）
let activeRequests = 0;

/**
 * 全局 HTTP 函数式拦截器
 * 
 * 功能特性：
 *  JWT 认证 - 自动添加和管理 JWT token
 *  Token 刷新 - 自动刷新过期 token
 *  加载状态 - 智能管理全局加载状态（支持并发请求）
 *  错误处理 - 统一处理各种 HTTP 错误
 *  路径过滤 - 只处理 API 请求，避免静态资源干扰
 */
export const globalHttpInterceptor: HttpInterceptorFn = (req, next) => {
  // 只拦截 API 请求
  if (!req.url.startsWith('/api/')) {
    return next(req);
  }

  const store = inject(Store);
  const authService = inject(AuthService);
  const config = getInterceptorConfig(req);

  // 更新加载状态
  updateLoadingState(store, config, true);

  // 根据认证状态选择不同的处理方式
  let observable$: Observable<HttpEvent<any>>;

  // 检查是否需要认证
  if (isTokenBasedAuthEntryPoint(req.url)) {
    if (!authService.getJwtToken() && !authService.refreshTokenPending()) {
      // 1：没有 token 且没有正在刷新 → 返回 401 错误
      observable$ = handleResponseError(req, next, new HttpErrorResponse({error: {message: 'Unauthorized!'}, status: 401}), authService);
    } else if (!authService.isJwtTokenValid()) {
      // 2：有 token 但 token 无效 → 标记需要刷新
      observable$ = handleResponseError(req, next, new HttpErrorResponse({error: {refreshTokenPending: true}}), authService);
    } else {
      // 3：有 token 且 token 有效 → 正常 JWT 拦截处理
      observable$ = jwtIntercept(req, next, authService);
    }
  } else {
    // 不需要认证的请求直接处理
    observable$ = handleRequest(req, next, authService);
  }

  // 请求完成后更新加载状态
  return observable$.pipe(
    finalize(() => {
      if (req.url.startsWith('/api/')) {
        updateLoadingState(store, config, false);
      }
    })
  );
};

/**
 * JWT 拦截处理
 * 为请求添加 JWT Token 认证头，然后发送请求
 */
function jwtIntercept(req: any, next: any, authService: AuthService): Observable<any> {
  // 更新请求头，添加 JWT Token
  const newReq = updateAuthorizationHeader(req, authService);
  if (newReq) {
    // 发送带有认证头的请求
    return handleRequest(newReq, next, authService);
  } else {
    // 无法获取 Token，抛出错误
    return throwError(() => new Error('Could not get JWT token from store.'));
  }
}

/**
 * 处理 HTTP 请求
 * 发送请求并捕获错误，统一进行错误处理
 */
function handleRequest(req: any, next: any, authService: AuthService): Observable<any> {
  return next(req).pipe(
    catchError((error) => {
      // 捕获请求错误，统一进行错误处理
      return handleResponseError(req, next, error as HttpErrorResponse, authService);
    })
  );
}

/**
 * 处理 HTTP 响应错误
 * 根据不同的错误类型进行相应的处理（Token 刷新、重试、错误通知等）
 */
function handleResponseError(req: any, next: any, errorResponse: HttpErrorResponse, authService: AuthService): Observable<any> {
  const config = getInterceptorConfig(req);
  let unhandled = false;
  const ignoreErrors = config.ignoreErrors;
  const resendRequest = config.resendRequest;
  const errorCode = errorResponse.error ? errorResponse.error.errorCode : null;

  // 处理认证相关错误（401 或 Token 刷新标记）
  if (errorResponse.error && errorResponse.error.refreshTokenPending ||
      errorResponse.status === 401 && req.url !== Constants.entryPoints.tokenRefresh) {
    if (errorResponse.error && errorResponse.error.refreshTokenPending ||
        errorCode && errorCode === Constants.serverErrorCode.jwtTokenExpired) {
      // Token 过期，尝试刷新并重试
      return refreshTokenAndRetry(req, next, authService);
    } else if (errorCode !== Constants.serverErrorCode.credentialsExpired) {
      // 其他认证错误，标记为未处理
      unhandled = true;
    }
  } 
  // 处理限流错误（429）
  else if (errorResponse.status === 429) {
    if (resendRequest) {
      // 配置允许重试，进行请求重试
      return retryRequest(req, next, authService);
    }
  } 
  // 处理权限错误（403）
  else if (errorResponse.status === 403) {
    if (!ignoreErrors) {
      showError('Forbidden');
    }
  } 
  // 处理网络连接错误（0 或 -1）
  else if (errorResponse.status === 0 || errorResponse.status === -1) {
    showError('Unable to connect');
  } 
  // 处理其他错误（排除 RPC 请求）
  else if (!(req.url.startsWith('/api/rpc') || req.url.startsWith('/api/plugins/rpc'))) {
    if (errorResponse.status === 404) {
      if (!ignoreErrors) {
        showError(req.method + ': ' + req.url + '<br/>' +
          errorResponse.status + ': ' + errorResponse.statusText);
      }
    } else {
      unhandled = true;
    }
  }

  // 处理未处理的错误
  if (unhandled && !ignoreErrors) {
    showError(errorResponse.message || 'Unknown error');
  }
  return throwError(() => errorResponse);
}

/**
 * 重试请求
 * 在限流错误（429）时，延迟随机时间后重新发送请求
 */
function retryRequest(req: any, next: any, authService: AuthService): Observable<any> {
  // 随机延迟 1-4 秒，避免所有请求同时重试
  const thisTimeout = 1000 + Math.random() * 3000;
  return of(null).pipe(
    delay(thisTimeout),
    mergeMap(() => jwtIntercept(req, next, authService))
  );
}

/**
 * 刷新 Token 并重试请求
 * 当 Token 过期时，自动刷新 Token 并重新发送原始请求
 */
function refreshTokenAndRetry(req: any, next: any, authService: AuthService): Observable<any> {
  return authService.refreshJwtToken().pipe(
    catchError((err: Error) => {
      // Token 刷新失败，执行登出操作
      authService.logout(true, true);
      const message = err ? err.message : 'Unauthorized!';
      return handleResponseError(req, next, new HttpErrorResponse({error: {message, timeout: 200}, status: 401}), authService);
    }),
    switchMap(() => jwtIntercept(req, next, authService))
  );
}

/**
 * 更新请求认证头
 * 为 HTTP 请求添加 JWT Token 认证头
 */
function updateAuthorizationHeader(req: any, authService: AuthService): any | null {
  const jwtToken = authService.getJwtToken();
  if (jwtToken) {
    return req.clone({
      headers: req.headers.set('X-Authorization', `Bearer ${jwtToken}`)
    });
  } else {
    // 无法获取 Token
    return null;
  }
}

/**
 * 检查是否为基于 Token 的认证入口点
 */
function isTokenBasedAuthEntryPoint(url: string): boolean {
  return url.startsWith('/api/') &&
    !url.startsWith(Constants.entryPoints.login) &&
    !url.startsWith(Constants.entryPoints.tokenRefresh) &&
    !url.startsWith(Constants.entryPoints.nonTokenBased);
}

/**
 * 更新加载状态（支持并发请求）
 * 
 * 问题：用户快速点击多个按钮时，加载指示器会频繁闪烁，第一个请求结束就隐藏加载但其他请求还在进行
 * 解决：使用请求计数器，只在第一个请求时显示加载，所有请求完成时隐藏加载
 */
function updateLoadingState(store: Store, config: InterceptorConfig, isLoading: boolean): void {
  if (!config.ignoreLoading) {
    if (isLoading) {
      activeRequests++;
    } else {
      activeRequests--;
    }
    
    // 只在第一个请求时显示加载，最后一个请求时隐藏加载
    if (activeRequests === 1 && isLoading) {
      store.dispatch(actionLoadStart()); // 第一个请求开始
    } else if (activeRequests === 0) {
      store.dispatch(actionLoadFinish());// 所有请求结束
    }
  }
}

/**
 * 显示错误信息
 * 将错误信息输出到控制台（待实现：集成通知服务）
 */
function showError(error: string, timeout: number = 0) {
  // TODO: 集成通知服务，显示用户友好的错误提示
  console.error({message: error, type: 'error'});
}
